﻿/**
* Provides utility methods for managing classes.
* 
* @author Kirill Mourzenko
*/

class com.kirillam.handy.util.ClassUtil
{
	/**
	 * Returns the full class name for an object.
	 * 
	 * @param	o	Object to get the classpath for.
	 * 
	 * @return	Full class name of the object.
	 */
	
	public	static function getClassPath( o : Object ) : String
	{
		if ( o.__hat_className == null ) {
			mapClassesToPaths();
		}
		
		return o.__hat_className;
	}
	
	
	/**
	 * Maps all existing classes to their class names.
	 */
	
	public	static function mapClassesToPaths()
	{
		mapPackageClasses( "", _global, 0 );
		_global[ "Function" ][ "prototype" ].__hat_className		= "Function";
	}
	
	
	private static function mapPackageClasses( prefix : String, package : Object, depth : Number )
	{
		if ( depth > 15 ) return;
		
		_global.ASSetPropFlags( package, null, 6, true );
		
		for ( var c : String in package ) {
			
			var o			: Object			= package[ c ];
			
			if( c.charAt( 0 ) == "_"  ) continue;
			
			var op			: Object			= o.prototype.__proto__;
			o.prototype.__proto__				= null;
			
			var className	: String			= o.prototype.__hat_className;
			o.prototype.__proto__				= op;
			
			if ( className != null ) continue;
			
			if ( o instanceof Function || typeof( o ) == "function" ) {
				
				o.prototype.__hat_className		= prefix + c;
				_global.ASSetPropFlags( o.prototype, "__hat_className", 7, true );
				
			} else if( !( o instanceof String ) &&  !( o instanceof Number ) && !( o instanceof Boolean ) && !( o instanceof Date ) ) {
				mapPackageClasses( prefix + c + ".", o, depth + 1 );
			}
		}
		
		_global.ASSetPropFlags( package, null, 7, true );
	}
	
	
	/** 
	 * Returns the name of method that it has inside a target object.
	 * 
	 * @param	o		Target object.
	 * @param	m		Method.
	 * 
	 * @return The name the method has inside the object.
	 */
	
	public static function getMethodName( o : Object, m : Function ) : String
	{
		if ( m.__hat_methodName != null ) return m.__hat_methodName;
		
		while ( o != null ) {
			
			_global.ASSetPropFlags( o, null, 0, true );
			
			for ( var p : String in o ) {
				
				if ( o[ "__get__" + p ] != null || o[ "__set__" + p ] != null ) {
					
					if ( o[ "__get__" + p ] === m || o[ "__set__" + p ] === m ) {
						
						m.__hat_methodName 	= getClassPath( o ) + "." + p;
						_global.ASSetPropFlags( o, null, 7, true );
						return m.__hat_methodName;
					}
				} else if( o[ p ] === m ) {
					
					m.__hat_methodName 		= getClassPath( o ) + "." + p;
					_global.ASSetPropFlags( o, null, 7, true );
					return m.__hat_methodName;
				}
			}
			
			_global.ASSetPropFlags( o, null, 7, true );
			
			o								= o.__proto__;
		}
		
		return null;
	}
}